import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { DatePipe } from '@angular/common';
import { Subject } from 'rxjs/Subject';

import { format as utilFormat } from 'util';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';

import { IPush } from './ipush.interface';
import { IHistory } from './ihistory.interface';
import { AppConfig } from '../../config';
import { TagProtocol, TagNode, TagType } from './tag-protocol';
import { IMPushService } from './impush.service';
import { HistoryService } from './history.service';
import { MockPushService } from './mock-push.service';
import { IMPushTestService } from './impush-test.service';
import { TagData } from '../../entity/tag-data.model';
import { MatrixData } from '../../entity/matrix-data';
import { FaultData } from '../../entity/fault-data';
import { TagMapService } from '../../service/tag-map.service';
import { Tag } from '../../entity/tag.model';
import { NzMessageService } from 'ng-zorro-antd';
import { ApplicationService } from '../../service/application.service';
import { InterceptorService } from '../../service/interceptor/interceptor-service';
import { SubstationData } from "../../entity/substation-data";
import { CodeHighlighter } from 'primeng/primeng';
import { fn } from '@angular/compiler/src/output/output_ast';

/**
 * 测点数据源服务
 *
 * @export
 * @class DataSourceService
 */
@Injectable()
export class DataSourceService {
    private readonly param = "tags/subTags";
    private get url(): string {
        return `${AppConfig.APP_RESTFUL}/${this.param}`;
    }

    /**
    * 主题对象数组
    *
    * @private
    * @type {Subject<any>[]}
    * @memberof IMPushService
    */
    private subjectMap: Subject<any>[] = [];
    private push: IPush;
    public history: IHistory;
    // 测点协议接口对象
    private protocol: TagProtocol;
    // 测点数据
    private tagDatas: TagData[];
    /**
     * Creates an instance of DataSourceService.
     * @param {IPush} push 实时数据推送服务
     * @param {IHistory} history 历史数据拉取服务
     * @memberof DataSourceService
     */

    constructor(


        // private http: Http,
        private http: InterceptorService,
        private datePipe: DatePipe,
        private _message?: NzMessageService,
        private application?:ApplicationService,
    ) {
        if (!AppConfig.APP_RANDOM) {
            this.push = new IMPushTestService();
        } else {
            this.push = new MockPushService(application);
        }
        this.history = new HistoryService(this.http, this.datePipe);
        this.protocol = new TagProtocol();
        this.tagDatas = [];
    }
    /**
     * 绑定测点
     *
     * @param {string[]} tagNodes
     * @param {string} tagCode
     * @returns {TagData}
     * @memberof DataSourceService
     */
    public binding(tagNodes: string[], tag: Tag): TagData {
    
        
        let code = this.buildTagCode(tagNodes, tag);        
        let tagData: TagData = null;
        if (code != '') {
            let index = this.tagDatas.findIndex(o => o.code === code);
            if (index >= 0) {
                tagData = this.tagDatas[index];
            }
            else {
                tagData = {
                    code: code,
                    value: 0,
                    status: 0,
                    time: new Date(),
                    tagUnit: tag.tagUnit,
                    tagName: tag.tagName,
                };
                this.tagDatas.push(tagData);
            }
        }
        else {
            tagData = {
                code: code,
                value: 0,
                status: 0,
                time: new Date()
            }
        }
        return tagData;
    }

    /**
    * 绑定测点
    *
    * @param {string[]} tagNodes
    * @param {string} tagCode
    * @returns {TagData}
    * @memberof DataSourceService
    */
    public bindingWhithCode(code: string): TagData {
        let tagData: TagData = null;
        if (code !== '') {
            const index = this.tagDatas.findIndex(o => o.code === code);
            if (index >= 0) {
                tagData = this.tagDatas[index];
            } else {
                tagData = {
                    code: code,
                    value: 0,
                    status: 0,
                    time: new Date(),
                };
                this.tagDatas.push(tagData);
            }
        } else {
            tagData = {
                code: code,
                value: 0,
                status: 0,
                time: new Date()
            };
        }
        return tagData;
    }

    /**
     * 开始订阅数据
     *
     * @returns {Subject<any>}
     * @memberof DataSourceService
     */
    public begin(): Subject<TagData[]> {
        this.buildTagProtocol();
        let subject: Subject<TagData[]> = new Subject();
        this.subjectMap.push(subject);
        this.push
            .begin(this.protocol)
            .subscribe(
                next => {
                    try {
                        let nextDatas: TagData[] = [];
                        next.forEach(nextData => {
                            let data = this.tagDatas.find(o => o.code === nextData.code);
                            if (data != null) {
                                try {
                                    data.value = nextData.value;
                                    data.time = nextData.time;
                                    data.status = nextData.status;
                                    nextDatas.push(nextData);
                                } catch (ex) {
                                    console.log(ex);
                                }
                            }

                        })
                        this.next(subject, nextDatas);

                    }
                    catch (error) {
                        console.log(error);
                    }
                },
                error => {
                    this.error(subject, error);
                });
        return subject;
    }

    public withHistories(start: Date, end: Date): Subject<{ historyData?: TagData[]; intervalData?: TagData[]; time?: Date }>;
    public withHistories(start: Date, end: Date, interval: number): Subject<{ historyData?: TagData[]; intervalData?: TagData[]; time?: Date }>;
    public withHistories(start: Date, end: Date, interval: { history: number; push: number; }): Subject<{ historyData?: TagData[]; intervalData?: TagData[]; time?: Date }>;
    public withHistories(start: Date, end: Date, interval?: any): Subject<{ historyData?: TagData[]; intervalData?: TagData[]; time?: Date }> {
        this.buildTagProtocol();
        let isFirst = true;
        let subject: Subject<any> = new Subject();
        this.subjectMap.push(subject);
        this.push.withHistories(this.protocol, start, end, interval)
            .subscribe(
                next => {
                    if (isFirst) {
                        try {
                            this.tagDatas.forEach(currTagData => {
                                let historyTagDatas = next.filter(historyTagData => historyTagData.code == currTagData.code);
                                if (historyTagDatas != null && historyTagDatas.length > 0) {
                                    let data = historyTagDatas.sort((a, b) => new Date(b.time).getTime() - new Date(a.time).getTime())[0];
                                    currTagData.time = data.time;
                                    currTagData.value = data.value;
                                    currTagData.status = data.status;
                                }
                            });
                            if (next != null && next.length && next.length > 0) {
                                this.next(subject, { historyData: next });
                            }
                        }
                        catch (error) {
                            this.error(subject, error);
                        }
                    }//推送历史数据
                    else {
                        try {
                            if (next != null && next.length && next.length > 0) {
                                let nextDatas: TagData[] = [];
                                next.forEach(nextData => {
                                    let data = this.tagDatas.find(o => o.code === nextData.code);
                                    if (data != null) {
                                        try {
                                            data.value = nextData.value;
                                            data.time = nextData.time;
                                            data.status = nextData.status;
                                        } catch (ex) {
                                            console.log(ex);
                                        }
                                    }
                                    nextDatas.push(nextData);
                                })
                                this.next(subject, {
                                    intervalData: nextDatas,
                                    time: new Date()
                                });

                            }
                        }
                        catch (error) {
                            this.error(subject, error);
                        }
                    }//推送实时数据

                    //第一次推送过来的是历史数据
                    if (isFirst)
                        isFirst = false;
                },
                error => {
                    this.error(subject, error);
                });
        return subject;
    }

    /**
     * 订阅风机矩阵数据
     *
     * @param {{tagId: number,farmIds: number[]}} matrix
     * @returns {Subject<any>}
     * @memberof IMPushService
     */
    public matrix(matrix: { tagId: number, farmIds: number[] }): Subject<MatrixData[]> {
        let subject: Subject<MatrixData[]> = new Subject();
        this.subjectMap.push(subject);
        this.push
            .matrix(matrix)
            .subscribe(
                next => {
                    try {
                        this.next(subject, next);
                    }
                    catch (error) {
                        this.error(subject, error);
                    }
                },
                error => {
                    this.error(subject, error);
                });
        return subject;
    }
    public alarmHistory(startTime, endTime, deviceIds: number[]): Subject<FaultData[]> {
        let subject: Subject<FaultData[]> = new Subject();
        this.subjectMap.push(subject);
        this.push
            .alarmHistory(startTime, endTime, deviceIds)
            .subscribe(
                next => {
                    try {
                        this.next(subject, next);
                    }
                    catch (error) {
                        this.error(subject, error);
                    }
                },
                error => {
                    this.error(subject, error);
                });
        return subject;
    }
    /**
     * 订阅风机报警数据
     *
     * @param {number} userId
     * @memberof DataSourceService
     */
    public alarm(userId: number): Subject<FaultData[]> {
        let subject: Subject<FaultData[]> = new Subject();
        this.subjectMap.push(subject);
        this.push
            .alarm(userId)
            .subscribe(
                next => {
                    try {
                        this.next(subject, next)
                    }
                    catch (error) {
                        this.error(subject, error);
                    }
                },
                error => {
                    this.error(subject, error);
                });
        return subject;
    }

    /**
     * 订阅升压站数据
     *
     * @param {number} userId
     * @memberof DataSourceService
     */
    public substation(userId: number): Subject<SubstationData[]> {
        let subject: Subject<SubstationData[]> = new Subject();
        this.subjectMap.push(subject);
        this.push
            .substation(userId)
            .subscribe(
                next => {
                    try {
                        this.next(subject, next)
                    }
                    catch (error) {
                        this.error(subject, error);
                    }
                },
                error => {
                    this.error(subject, error);
                });
        return subject;
    }



    /**
     * 构建测点编码
     *
     * @param {string[]} tagNodes
     * @param {string} tagCode
     * @returns {string}
     * @memberof DataSourceService
   
  
    public buildTagCode(tagNodes: string[], tag: Tag): string {
        if (tagNodes == null)
            return '';
        if (tagNodes.length <= 0)
            return '';
        //去除节点中的空格
        tagNodes.map(o => o = o.trim());
        if (tagNodes.findIndex(o => o === '') >= 0)
            return '';
        if (tag == undefined || tag == null)
            return '';
        //如果是自己定义的计算点（表名加CL，）
        if (!tag.tagDefinition) {
            let farmCode = tagNodes[0];
            let farmCodeArray = farmCode.split('.');
            farmCodeArray[0] = `${farmCodeArray[0]}CAL`;
            tagNodes[0] = farmCodeArray.join('.');
        }
        let code: string = this.protocol.format;
        //格式化编码
        tagNodes.forEach(node => {
            code = utilFormat(code, node);
        });
        code = utilFormat(code, tag.tagCode);

        //将多余部分的连接符去掉
        while (code.endsWith(this.protocol.connector)) {
            code = code.replace(this.protocol.connector, '');
        }
        code = code.substr(0, code.length - 1);
        return code;
    }
    */

   public buildTagCode(tagNodes: string[], tag: Tag): string {
    if (tagNodes == null)
        return '';
    if (tagNodes.length <= 0)
        return '';
    let deviceCode= null;
    if(tagNodes.length > 1){  deviceCode = tagNodes[1];}
    //去除节点中的空格
    tagNodes.map(o => o = o.trim());
    if (tagNodes.findIndex(o => o === '') >= 0)
        return '';
    if (tag == undefined || tag == null)
        return '';
    //如果是自己定义的计算点（表名加CL，）
    let farmCode = tagNodes[0];
    let farmCodeArray = farmCode.split('.');

    if (tag.tagType == '2') {        
        farmCodeArray[0] = `${farmCodeArray[0]}CAL`;
        tagNodes[0] = farmCodeArray.join('.');
    }else if(tag.tagType == '3'){
        farmCodeArray[0] = `${farmCodeArray[0]}1Q`;
        tagNodes[0] = farmCodeArray.join('.');
    }

    let code: string = this.protocol.format;
    //格式化编码
    tagNodes.forEach(node => {
        code = utilFormat(code, node);
    });
    code = utilFormat(code, tag.tagCode);

    //将多余部分的连接符去掉
    while (code.endsWith(this.protocol.connector)) {
        code = code.replace(this.protocol.connector, '');
    }
    code = code.substr(0, code.length - 1);
    if(farmCode.indexOf(".MX_") != -1 && (deviceCode != null) && (deviceCode.startsWith('13_') || deviceCode.startsWith('11_')) && tag.tagType !='2'){
        let index = code.lastIndexOf('_');
        code = code.substring(0,index)+code.substring(index+1,code.length)
    }
    return code;
}
/**
    public buildTagCode(tagNodes: string[], tag: Tag):any {    
    let farmCode = null;
    let deviceCode= null;
    if(tagNodes==null){ return ""}
    if (tag == undefined || tag == null) return '';

    if (tagNodes.length <= 0) return '';
        farmCode = tagNodes[0];
    if(tagNodes.length > 1){  deviceCode = tagNodes[1];}
    
    let tagCode = tag.tagCode;
    let tagType = tag.tagType;
    // let resqustUrl = `${this.url}/cirCuits`;
    let resqustUrl = `${this.url}/farmCode/${farmCode}/deviceCode/${deviceCode}/tagCode/${tagCode}/tagType/${tagType}`;
    // http://192.168.15.25:8585/webapi/v1/subTags/farmCode/MM.MX_MM_1/deviceCode/001/tagCode/Communication/tagType/3
    let result = this.fn(farmCode,deviceCode,tagCode,tagType); 
    return result;
    // this.http.get(resqustUrl) 
    //     .toPromise()
    //     .then(response => {           
    //         return response.json().data
    //     })
    //     .catch(this.handleError);        
}

    private fn(farmCode,deviceCode,tagCode,tagType){
        let resqustUrl = `${this.url}/farmCode/${farmCode}/deviceCode/${deviceCode}/tagCode/${tagCode}/tagType/${tagType}`;
        this.http.get(resqustUrl) 
        .toPromise()
        .then(response => {           
            return response.json().data
        })
        .catch(this.handleError);
    }


    

    private handleError(error: any): Promise<any> {
        return Promise.reject(error.message || error);
    }
 */ 

    /**
     * 构建测点协议
     *
     * @private
     * @memberof DataSourceService
     */
    private buildTagProtocol() {
        this.protocol.tagArrary = this.tagDatas.map(o => o.code);
    }

    private error(subject: Subject<any>, error: Error) {
        if (subject != null && !subject.closed && !subject.isStopped) {
            console.log('实时数据服务' + error);
            subject.error(error);
        }
    }

    private next(subject: Subject<any>, data: any) {
        if (subject != null && !subject.closed && !subject.isStopped) {
            subject.next(data);
        }
    }

    /**
     * 释放资源
     *
     * @memberof DataSourceService
     */
    public dispose() {
        this.history.dispose();
        this.push.close();
        if (this.subjectMap) {
            this.subjectMap.forEach(map => {
                map.unsubscribe();
                map = null;
            });
            this.subjectMap = null;
        }

    }


}









// WEBPACK FOOTER //
// ./src/app/service/data-source/data-source.service.ts